# -*- coding: utf-8 -*-
import logging
import os
import socket
import sys
from PyQt4 import QtGui, QtCore
from multiprocessing import Pipe, Process

from PyQt4.QtGui import *

sys.path.append('..')
from transfer import sender
from transfer.receiver import Receiver
from transfer.sender import Sender, PORT_FILE, PORT_DIGEST, LOCALHOST, PORT_WAITING
from sniffer.sniffer import Sniffer
from transfer.common import isUserAdmin

LOG = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)

HEAD, TAIL = Pipe()


class TransferWindow(QtGui.QWidget):
    def __init__(self):
        super(TransferWindow, self).__init__()
        self.grid = QtGui.QGridLayout()
        self.setWindowTitle("summerTerm")
        self.init_UI()
        self.waiting_thread = WaitingThread()
        QtCore.QObject.connect(self.waiting_thread, QtCore.SIGNAL('knock'), self.get_knock)
        self.waiting_thread.start()

    def init_UI(self):
        while self.grid.count():
            item = self.grid.takeAt(0)
            widget = item.widget()
            widget.deleteLater()
        self.button_transfer = QtGui.QPushButton("transfer")
        self.button_transfer.clicked.connect(self.transfer_UI)
        self.button_sniffer = QtGui.QPushButton('sniffer', self)
        self.button_sniffer.clicked.connect(self.sniffer_UI)

        self.grid.setSpacing(10)

        self.grid.addWidget(self.button_transfer, 1, 0)
        self.grid.addWidget(self.button_sniffer, 1, 1)

        self.setLayout(self.grid)
        self.resize(300, 300)

    def transfer_UI(self):
        while self.grid.count():
            item = self.grid.takeAt(0)
            widget = item.widget()
            widget.deleteLater()
        self.button_send = QtGui.QPushButton('send', self)
        self.button_send.clicked.connect(self.send)
        self.button_cancel = QtGui.QPushButton('cancel', self)
        self.button_cancel.clicked.connect(self.cancel)
        self.button_back = QtGui.QPushButton('back', self)
        self.button_back.clicked.connect(self.init_UI)

        self.address_edit = QtGui.QLineEdit()
        self.address_edit.setPlaceholderText("Here is your file address")
        self.host_edit = QtGui.QLineEdit()
        self.host_edit.setPlaceholderText("Please input the receiver IP")

        self.grid.setSpacing(10)

        self.grid.addWidget(self.button_send, 1, 0)
        self.grid.addWidget(self.button_cancel, 2, 0)
        self.grid.addWidget(self.address_edit, 3, 0)
        self.grid.addWidget(self.host_edit, 4, 0)
        self.grid.addWidget(self.button_back, 5, 0)

        self.setLayout(self.grid)

        self.resize(300, 300)

    def sniffer_UI(self):
        while self.grid.count():
            item = self.grid.takeAt(0)
            widget = item.widget()
            widget.deleteLater()
        self.button_sniff = QtGui.QPushButton('sniff', self)
        self.button_sniff.clicked.connect(self.sniff)
        self.button_stop = QtGui.QPushButton('stop', self)
        self.button_stop.clicked.connect(self.stop)
        self.button_clear = QtGui.QPushButton('clear', self)
        self.button_clear.clicked.connect(self.clear)
        self.browser = QTextBrowser()
        self.button_back = QtGui.QPushButton('back', self)
        self.button_back.clicked.connect(self.init_UI)

        self.grid.setSpacing(10)

        self.grid.addWidget(self.button_sniff, 1, 0)
        self.grid.addWidget(self.button_stop, 2, 0)
        self.grid.addWidget(self.button_clear, 3, 0)
        self.grid.addWidget(self.browser, 4, 0)
        self.grid.addWidget(self.button_back, 5, 0)

        self.setLayout(self.grid)

        self.resize(500, 500)

    def update_text(self, package):
        self.browser.append(package)

    def clear(self):
        self.browser.clear()

    def transfer_success(self):
        QtGui.QMessageBox.about(self, "info", "get")

    def transfer_fail(self):
        QtGui.QMessageBox.about(self, "error", "failed")

    def get_knock(self, conn, addr):
        reply = QtGui.QMessageBox.question(self, 'new file', 'new file from %s,accept?' % addr[0],
                                           QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        conn.close()
        if reply == QtGui.QMessageBox.Yes:
            self.waiting_thread.terminate()
            self.receive(addr[0])
            self.waiting_thread.start()

    def select_send_address(self):
        os.chdir(os.path.expanduser('~/Desktop'))
        absolute_path = QFileDialog.getOpenFileName(self, 'Open file', '.', "all files (*.*)")
        self.address_edit.setText(absolute_path)
        self.address_edit.setDisabled(True)

    def select_rece_address(self):
        os.chdir(os.path.expanduser('~/Desktop'))
        absolute_path = QFileDialog.getSaveFileName(self, 'Save file', '.', "all files (*.*)")
        self.address_edit.setText(absolute_path)
        self.address_edit.setDisabled(True)

    def send(self):
        self.waiting_thread.terminate()
        dst_host = self.host_edit.text()
        if dst_host == '':
            QtGui.QMessageBox.about(self, "info", "input destination host first!")
            return
        self.select_send_address()
        if self.address_edit.text() == '':
            return
        try:
            self.s = socket.socket()
            self.s.connect((dst_host, PORT_WAITING))
        except Exception as e:
            QtGui.QMessageBox.about(self, "error", "network error")
        self.send_thread = SendingThread(file_path=self.address_edit.text(), dst_host=self.host_edit.text())
        QtCore.QObject.connect(self.send_thread, QtCore.SIGNAL('success'), self.transfer_success)
        QtCore.QObject.connect(self.send_thread, QtCore.SIGNAL('fail'), self.transfer_fail)
        self.send_thread.start()

    def receive(self, host):
        self.select_rece_address()
        self.rece_thread = ReceiveThread(file_path=self.address_edit.text(), host=host)
        QtCore.QObject.connect(self.rece_thread, QtCore.SIGNAL('success'), self.transfer_success)
        QtCore.QObject.connect(self.rece_thread, QtCore.SIGNAL('fail'), self.transfer_fail)
        self.rece_thread.start()

    def cancel(self):
        self.rece_thread.terminate()
        self.send_thread.terminate()
        self.waiting_thread.start()

    @staticmethod
    def prn(package):
        HEAD.send(str(package))

    @staticmethod
    def _sniff():
        sniffer = Sniffer(prn=TransferWindow.prn)
        sniffer.sniff()

    def sniff(self):
        if not isUserAdmin():
            QtGui.QMessageBox.about(self, 'error', 'neet to run as root')
            return
        self.sniff_process = Process(target=TransferWindow._sniff)
        self.sniff_process.start()
        self.sniff_thread = SniffThread()
        QtCore.QObject.connect(self.sniff_thread, QtCore.SIGNAL('newPackage'), self.update_text)
        self.sniff_thread.start()

    def stop(self):
        self.sniff_process.terminate()
        self.sniff_process.join()
        self.sniff_thread.terminate()
        self.sniff_thread.wait()


class SendingThread(QtCore.QThread):
    def __init__(self, file_path, dst_host, parent=None):
        super(SendingThread, self).__init__(parent)
        self.file_path = file_path
        self.dst_host = dst_host

    def run(self):
        try:
            send_address = self.file_path
            server = Sender(PORT_FILE)
            server.accept()
            server.shake_hand()
            server.send_file(send_address)
            server1 = Sender(PORT_DIGEST)
            server1.send_digest(send_address)
        except Exception as e:
            LOG.error(e)
            self.emit(QtCore.SIGNAL('fail'))
            return

        self.emit(QtCore.SIGNAL('success'))


class WaitingThread(QtCore.QThread):
    def __init__(self, parent=None):
        super(WaitingThread, self).__init__(parent)
        try:
            self.s = socket.socket()
            self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.s.bind((LOCALHOST, PORT_WAITING))
            self.s.listen(5)
            LOG.debug('waiting in %s,%s' % (LOCALHOST, PORT_WAITING))
        except Exception as e:
            LOG.error(e)
            self.s = None

    def run(self):
        while True:
            if self.s is not None:
                self.conn, self.addr = self.s.accept()
                LOG.debug('Got connection from %s', str(self.addr))
                self.emit(QtCore.SIGNAL('knock'), self.conn, self.addr)


class ReceiveThread(QtCore.QThread):
    def __init__(self, file_path, host, parent=None):
        super(ReceiveThread, self).__init__(parent)
        self.file_path = file_path
        self.server_host = host

    def run(self):
        try:
            rece_address = self.file_path
            client = Receiver(self.server_host, sender.PORT_FILE)
            client.shake_hand()
            client.receive_file(rece_address)
            client1 = Receiver(self.server_host, sender.PORT_DIGEST)
            client1.check_file(rece_address)
        except Exception as e:
            LOG.error(e)
            self.emit(QtCore.SIGNAL('fail'))
            return
        self.emit(QtCore.SIGNAL('success'))


class SniffThread(QtCore.QThread):
    def __init__(self, parent=None):
        super(SniffThread, self).__init__(parent)

    def run(self):
        while True:
            package = TAIL.recv()
            LOG.debug(package)
            self.emit(QtCore.SIGNAL('newPackage'), package)


def main():
    app = QtGui.QApplication(sys.argv)
    transfer_window = TransferWindow()
    transfer_window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
